﻿using Algorithm.Check;
using Common;
using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static Algorithm.Check.ExtensionForCRC16;

namespace T68Control.Procdure
{
    /// <summary>
    /// 万瑞达直流电源 型号：RU-18-10001 输入电压：220V 输出电压：0-1000V 输出电流：0-1A
    /// </summary>
    internal class RU_18_10001
    {
        private static string deviceName = "高压电源RU-18";
        private static SerialPort serialPort;
        private static bool isConnected = false;

        [Conditional("DEVICE")]
        public static void Connect(string port, int baud = 9600)
        {
            serialPort = new SerialPort();
            serialPort.BaudRate = baud;
            serialPort.PortName = port;

            ManualResetEventSlim openCompletedEvent = new ManualResetEventSlim(false);
            Task.Run(() =>
            {
                serialPort.Open();
                openCompletedEvent.Set();
            });
            if (!openCompletedEvent.Wait(2000))
            {
                throw new Exception($"{deviceName}连接异常");
            }
            isConnected = true;
        }

        /// <summary>
        /// 设置电压
        /// </summary>
        /// <param name="vol"> </param>
        /// <exception cref="Exception"> </exception>
        [Conditional("DEVICE")]
        public static void SetVoltage(double volInput)
        {
            int vol = (int)(volInput * 100);
            if (!isConnected)
            {
                return;
            }
            byte[] data = new byte[] { 0x01, 06, 00, 0x95, (byte)((vol & 0xff00) >> 8), (byte)(vol & 0xff), };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            var recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"{deviceName} SetVoltage 返回数据异常");
                throw new Exception($"{deviceName} SetVoltage 返回数据异常");
            }
        }

        /// <summary>
        /// 读取电压
        /// </summary>
        /// <returns> </returns>
        /// <exception cref="Exception"> </exception>
        public static double GetVoltage()
        {
            if (!isConnected)
            {
                return 0;
            }
            byte[] data = new byte[] { 0x01, 03, 00, 0x95, 00, 01 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            var recv = SendCmdAndWaitReturn(cmd);
            if (recv.Length != 7)
            {
                Mylog.Debug($"{deviceName} GetVoltage 返回数据异常");
                throw new Exception($"{deviceName} GetVoltage 返回数据异常");
            }
            return (double)(((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF)) / 100.0;
        }

        public static double GetCurrent()
        {
            if (!isConnected)
            {
                return 0;
            }
            byte[] data = new byte[] { 0x01, 03, 00, 0x96, 00, 01 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            var recv = SendCmdAndWaitReturn(cmd);
            if (recv.Length != 7)
            {
                Mylog.Debug($"{deviceName} GetCurrent 返回数据异常");
                throw new Exception($"{deviceName} GetCurrent 返回数据异常");
            }
            return (double)(((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF)) / 100;
        }

        [Conditional("DEVICE")]
        public static void SetStatus(bool isOn)
        {
            if (!isConnected)
            {
                return;
            }
            byte[] data = new byte[] { 01, 05, 00, 0x85, (byte)(isOn ? 0xff : 0x00), 0x00 };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            var recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"{deviceName} SetStatus 返回数据异常");
                throw new Exception($"{deviceName} SetStatus 返回数据异常");
            }
        }

        /// <summary>
        /// 设置输出电流
        /// </summary>
        /// <param name="cur"> 0.001-1A </param>
        [Conditional("DEVICE")]
        public static void SetCurrent(double cur)
        {
            if (!isConnected)
            {
                return;
            }
            int tmp = (int)(cur * 100);
            byte[] data = new byte[] { 0x01, 06, 00, 0x96, (byte)((tmp & 0xff00) >> 8), (byte)(tmp & 0xff), };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            var recv = SendCmdAndWaitReturn(cmd);
            if (!recv.SequenceEqual(cmd))
            {
                Mylog.Debug($"{deviceName} SetCurrent 返回数据异常");
                throw new Exception($"{deviceName} SetCurrent 返回数据异常");
            }
        }

        private static byte[] SendCmdAndWaitReturn(byte[] cmd)
        {
            Mylog.Debug($"[{deviceName}] sendCmd [{BitConverter.ToString(cmd).Replace('-', ' ')}]");
            serialPort.DiscardInBuffer();
            serialPort.Write(cmd, 0, cmd.Length);
            Thread.Sleep(50);
            if (serialPort.BytesToRead > 0)
            {
                byte[] recv = new byte[serialPort.BytesToRead];
                serialPort.Read(recv, 0, recv.Length);
                Mylog.Debug($"[{deviceName}] recvCmd [{BitConverter.ToString(recv).Replace('-', ' ')}]");

                return recv;
            }
            throw new Exception($"[{deviceName}]未收到数据");
        }
    }
}